﻿//
// Created by gogoqiu on 2022/1/12.
//

#include <stdio.h>
#include <wx/wx.h>
//#define FILE_LOG _T("d:\\clientV1.log")
//#define MY_SCP_PATH "/mnt/db"
#include <objbase.h>
#include <wx/file.h>
#include <wx/filename.h>
#include <mysql.h>
#include <string>
#include "action_event.h"
#include "ids.h"
#include "scp.h"
#include "func.h"

using namespace std;

extern bool log_to_file;
extern string log_filename;

extern string remote_mysql_ip;
extern int  remote_mysql_port;
extern string mysql_user;
extern string mysql_password;
extern string mysql_database;

extern string remote_ssh_ip;
extern int  remote_ssh_port;
extern string ssh_user;
extern string ssh_password;
extern string ssh_remote_path;

static void done( wxWindow *parent ){
    if( parent== nullptr ){
        wxPrintf( "done!\n" );
    }else{
        ActionEvent event1( parent, TOKEN_ACTION_END );
        event1.Post();
    }
}

int gen_uuid( char* buf ){
    GUID guid;
    HRESULT h = CoCreateGuid(&guid);
    if (h == S_OK) {
        sprintf_s( buf, sizeof(buf),
                  "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
                  guid.Data1, guid.Data2, guid.Data3,
                  guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
                  guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
    }else
        return -1;
    return 0;
}

static wxString gen_uuid_string(){
    wxString tmp;
    GUID guid;
    HRESULT h = CoCreateGuid(&guid);
    tmp.sprintf( _T("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"),
                 guid.Data1, guid.Data2, guid.Data3,
                 guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
                 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
    return tmp;
}

//critical error: log can't write
//
static void writeLog( wxFile* logFile, wxString log ){
    if( logFile->IsOpened() )
        logFile->Write( log );
}

void RepSession::addLog( const wxString& log ){
    if( parent!= nullptr ) {
        //by message
        ActionEvent event(parent, TOKEN_LOG, log);
        event.Post();
    }else{
        //by stdout
        //wxPrintf( "%s\n", log );
        wxString tmp;
        tmp.sprintf( "%s\n", log );
        std::cout << tmp.mbc_str();
    }
    if( log_to_file ){
        writeLog( logFile, log );
    }
}

//collect all info
void RepSession::init( wxFileName fileName, wxWindow *parent,
        MYSQL *conn_ptr, bool should_delete_file ) {
    this->parent = parent;
    this->fileName = fileName;
    this->conn_ptr = conn_ptr;
    this->should_delete_file = should_delete_file;
    this->item = new Item();
    //memset( item, sizeof( Item ), 1 );
    this->item->path = fileName.GetFullPath();
    this->item->name = fileName.GetFullName();
    this->item->size = fileName.GetSize().GetValue();
    this->item->lastModified = fileName.GetModificationTime().GetValue().GetValue();
    this->item->uuid = gen_uuid_string();
    logFile = new wxFile();
    if( !wxFile::Exists( log_filename ) ){
        logFile->Create( ( log_filename ),true );
    }
}

int RepSession::realScp( wxWindow *parent, const wxFileName& localFile,
                         const wxString& uuid, char* md5sum, char* md4sum ){
    //
    //const char *localFile = path.mb_str(wxConvUTF8);
    wxString tmp;
    tmp.sprintf( "%s/%s", ssh_remote_path, uuid );
    const char *dest = tmp.mb_str(wxConvUTF8);
    //MY_SCP_PATH
    wxString log;
    log.sprintf( "拷贝至%s", dest );
    addLog( log );
    return scp_md5sum( parent, localFile, dest, md5sum, md4sum );
}

int RepSession::scpRep() {
    char md5sum[255] = {0};
    char md4sum[255] = {0};
    if( realScp( parent, fileName,
            this->item->uuid, md5sum, md4sum ) ){
        addLog( "拷贝出错" );
        return -1;
    }
    wxString tmp;
    tmp.sprintf( "md4: %s", md4sum );
    addLog( tmp );
    this->item->md5 = md5sum;
    return 0;
}

wxString RepSession::buildSql (  )
{
    wxString sql;
    item->path.Replace("\\", "\\\\");
    item->path.Replace("\"", "\\\"");
    item->path.Replace("\'", "\\\'");;
    wxString _path = item->path;
    sql.sprintf ( _T( "INSERT INTO `repository` ( `uuid`, `name`, `size`, `md5`, "
                      "`lastmodified`, `mime`, `path`, `accessType`, `filetype`, "
                      "`recordtime`, `content`, `tags`) "
                      "VALUES( '%s', '%s', %lld, '%s', %lld, '%s', '%s', %d, %d, NOW(), '%s', '%s' );"),
                  item->uuid, item->name, item->size, item->md5, item->lastModified,
                  item->mime,
                  _path,
                  item->accessType, item->fileType, item->content, item->tags );
    //printf ( "%s\n", sql );
    return sql;
}

int RepSession::record( ) {
    const char* _sql;
    wxString sql = buildSql();
    wxPrintf( "%s\n", sql );
    _sql = sql.mb_str(wxConvUTF8);
    int retVal;
    if ( _sql != nullptr && conn_ptr!= nullptr ) {
        retVal = mysql_query(conn_ptr, "SET NAMES UTF8");
        /*
        if( retVal !=0 ){
            reconnect();
            mysql_query(conn_ptr, "SET NAMES UTF8");
        }*/
        retVal = mysql_query(conn_ptr, _sql);
        if (retVal != 0) {
            addLog( mysql_error(conn_ptr) );
            addLog( sql );
            return -1;
        }
    } else
        return -1;
    return 0;
}

RepSession::~RepSession() {
    if( item )
        delete item;
    if( logFile )
        delete logFile;
}

void RepSession::postFile() {
    wxString log;
    log.sprintf( _T("上传: %s"), this->item->path );
    addMySqlLog( log );

    if ( scpRep() == 0 ) {
        addLog( this->item->path );
        addLog( "文件信息已上传");
        addMySqlLog(_("文件信息已上传"));
        if ( record() == 0 ) {
            //文件信息到日志
            //清空file pick
            //this->start_post_button->Enable();
            //
            addLog( "文件信息已记录");
            addMySqlLog("文件信息已记录");
            if( should_delete_file ){
                //preference, alert box
                //wxFile file( this->item->path );
                if( wxRemoveFile( this->item->path ) ){
                    addLog( "文件已删");
                    addMySqlLog("文件已删");
                }else{
                    addLog( "文件删除失败");
                    addMySqlLog("文件删除失败");
                }
            }
            done( parent );
        } else {
            addLog( "record fail...");
            addMySqlLog("record fail...");
        }
    } else {
        //add log
        //post log
        //log control, 定向消息
        //post percent
        addLog( "scp fail..." );
        addMySqlLog("scp fail...");
    }
}

void RepSession::addMySqlLog( wxString log ){
    log.Replace("\\", "\\\\");
    log.Replace("\"", "\\\"");
    log.Replace("\'", "\\\'");;
    wxString tmp;
    wxString computerName =::wxGetFullHostName();
    if( log.EndsWith("\n")){
        tmp = log.SubString( 0, log.Len()-2 );
    }else{
        tmp = log;
    }
    const char* _sql;
    wxString sql;
    sql.sprintf( _T("insert into log( `datetime`, host, log ) values( NOW(), '%s', '%s' );" )
            , computerName, tmp );
    _sql = sql.mb_str(wxConvUTF8);
    int retVal;
    if ( _sql != nullptr && conn_ptr!= nullptr ) {
        retVal = mysql_query(conn_ptr, "SET NAMES UTF8");
        retVal = mysql_query(conn_ptr, _sql);
    }
}

int RepSession::reconnect() {
    conn_ptr = mysql_real_connect( conn_ptr, remote_mysql_ip.c_str(),
                mysql_user.c_str(), mysql_password.c_str(),
                mysql_database.c_str(), remote_mysql_port, nullptr, 0);
    if (!conn_ptr) {
        addLog( "mysql连接失败");
    }else
        addLog( "mysql已连接");
    return 0;
}
